package com.etrans.web.gps.business.checktask.service;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

import org.bson.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.etrans.egov.base.cmd.obj.CmdArgsPostQueryReq;
import com.etrans.egov.base.cmd.obj.CmdIds;
import com.etrans.egov.base.cmd.obj.ObjCmdReceipt;
import com.etrans.egov.base.cmd.obj.ObjCmdReply;
import com.etrans.egov.base.cmd.obj.ObjCmdRequest;
import com.etrans.egov.base.packet809.Packet;
import com.etrans.egov.base.packet809.uitls.Packet809Utils;
import com.etrans.web.gps.base.service.BaseService;
import com.etrans.web.gps.business.checktask.domain.AreaCheck;
import com.etrans.web.gps.business.checktask.domain.EntCheck;
import com.etrans.web.gps.business.checktask.domain.EntCheckCmd;
import com.etrans.web.gps.business.checktask.domain.EnterpriseVO;
import com.etrans.web.gps.business.checktask.domain.PlatformVO;
import com.etrans.web.gps.business.checktask.domain.Strategy;
import com.etrans.web.gps.business.checktask.enums.CheckResult;
import com.etrans.web.gps.business.checktask.enums.CheckType;
import com.etrans.web.gps.business.command.controller.Net2CmdProducer;
import com.etrans.web.gps.common.MGTemplete;
import com.etrans.web.gps.util.Config;
import com.etrans.web.gps.util.MongodbConfig;
import com.mongodb.BasicDBObject;
import com.mongodb.client.model.UpdateOptions;

@Service
public class CheckTaskService extends BaseService  {

	private static final Logger logger = LoggerFactory.getLogger(CheckTaskService.class);

	@Autowired
	private EnterpriseService enterpriseService;

	@Autowired
	private PlatformService platformService;

	@Autowired
	private MGTemplete mgTemplete; // mongodb 操作类
	
	@Autowired  
    private Config config; //引用统一的参数配置类  

	
	/**
	 * 查岗策略设置列表查询 查岗类型： 1：业户 2：区域（即管理机构）
	 * 
	 * @return List<Strategy>
	 */
	public List<Strategy> queryAllStrategys(Map<String, Object> params) {
		return this.selectList("strategyQuery.queryAllStrategys", params);
	}

	
	/**
	 * 策略设置表修改
	 * @param strategy
	 * @return
	 */
	public int updateStrategys(Strategy strategy) {
		return this.update("strategyMapper.updateStrategys", strategy);
	}
	/**
	 * 根据区域id 查询区域名称
	 * @param id
	 * @return
	 */
	public Map<String,String> queryAreaName(int id){
		return this.selectOne("strategyQuery.queryAreaName", id);
	}
	
	
	
	/**
	 * 业户自动查岗任务
	 */
	public void taskCheck() {
		ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
		executor.scheduleAtFixedRate(new TaskCheckServer(), 0, config.checkTaskTimers, // 一小时执行一次
				TimeUnit.MILLISECONDS);
		logger.info("业户自动查岗任务{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{{}进入线程方法{}{} " 
				+ System.currentTimeMillis() + ".");
	}


	/**
	 * 业户线程
	 * @author Tan
	 *
	 */
	class TaskCheckServer implements Runnable {
		SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
		@SuppressWarnings("null")
		@Override
		public void run() {
			logger.info("{}{}====start====>业户自动定时任务线程."
					+ " The current time is " + format.format(new Date()) + ".");
			try {

				Map<String, Object> map = new HashMap<>();
				// 开始时间->当前时间
				String startTime = format.format(new Date());
				long curren = System.currentTimeMillis();
				curren += config.checkTaskTimers;
				Date date = new Date(curren);
				// 结束时间->当前时间加一小时
				String endTime = format.format(date);
				map.put("startTime", startTime);
				map.put("endTime", endTime);
				// 自动任务查询
				List<Strategy> list = queryAllStrategys(map);
				if (list != null && list.size() > 0) {
					for (Strategy strategy : list) {
						if (strategy.getCheckType() == 1) {// 业户
							int enterpriseId = Integer.valueOf(strategy.getCheckTargetId()); 					// 业户id
							EnterpriseVO enterpriseVO = enterpriseService.queryEnterpriseById(enterpriseId);	// 根据业户id 查询 平台接入id
							int gnss_center_id = 0;
							if (enterpriseVO != null) {
								// 平台接入id
								int platformId = enterpriseVO.getPlatformId();
								PlatformVO platformVO = platformService.queryPlatformById(platformId);
								if (platformVO != null) {
									gnss_center_id = platformVO.getAccessCenterCode();
									logger.info("成功获取平台接入码 platformVO.getAccessCenterCode(): {}",
											platformVO.getAccessCenterCode());
								} else {
									logger.info("无法获取平台接入码 platformVO.getAccessCenterCode(): {}",
											platformVO.getAccessCenterCode());
								}
							} else {
								logger.info("无法获取获取平台接入id: enterpriseVO.getPlatformId(){}",
										enterpriseVO.getPlatformId());
							}
							String object_id = enterpriseVO.getBizLicenseNum().trim();
							int object_type = CheckType.CHECK_TYPE_TWO;
							// 业户名称
							String checkUnitName = enterpriseVO.getName();
							// 执行->指令发送->策略表修改->mongodb插入
							sendtask(strategy, gnss_center_id, object_id, object_type, checkUnitName);
						}
						else if (strategy.getCheckType() == 2) { // 区域(即管理机构)
							// 执行->策略表修改->mongodb插入
							task(strategy);
						} else {
							logger.info("========》{}其它暂时预留========》");
						}
					}
				}

			} catch (Exception e) {
				e.printStackTrace();
			}
			logger.info("{}{}====end====>业户自动定时任务线程. The current time is "
			+ format.format(new Date()) + ".");
		}
	}

	// 执行->指令发送->策略表修改->mongodb插入
	@SuppressWarnings("static-access")
	public void sendtask(Strategy strategy, int gnss_center_id, String object_id, int object_type,
			String checkUnitName) {
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		logger.info("===============>gnss_center_id=============>" + gnss_center_id
				+ "  ===============>object_id=================>" + object_id
				+ "  ===============>object_type=================>" + object_type
				+ "  ===============>checkUnitName=================>" + checkUnitName);
		// 1.发指令
		// commander 连接
		Net2CmdProducer cmdProducer = new Net2CmdProducer(config.commanderPath,
				config.commanderPort);
		cmdProducer.start();
		if(cmdProducer.getClient().isConnected()){
			// 查岗id
			int info_id = ThreadLocalRandom.current().nextInt();
			// 数据包封装
			CmdArgsPostQueryReq cmdArgsPostQueryReq = new CmdArgsPostQueryReq();
			cmdArgsPostQueryReq.setGnssCenterId(gnss_center_id); 							// 平台接入id
			cmdArgsPostQueryReq.setObjectType((byte) object_type);
			cmdArgsPostQueryReq.setObjectId(object_id); 									// 下发的业户id
			cmdArgsPostQueryReq.setInfoId(info_id); 										// 查岗id
			cmdArgsPostQueryReq.setInfoContent(strategy.getQuestion()); 					// 题库问题名称
			logger.info("cmdArgsPostQueryReq: {}", cmdArgsPostQueryReq.toJSONObject());
			ObjCmdRequest objCmd = new ObjCmdRequest();
			objCmd.setCmdId(CmdIds.CMD_ID_POST_QUERY_REQ);
			objCmd.setArgs(cmdArgsPostQueryReq.toJSONObject().toString());
			objCmd.setReceiptTimeout(5000);
			objCmd.setReplyTimeout(1000 * 60 * 15);
			try {
				cmdProducer.push(objCmd, new Net2CmdProducer.Callback() {
					@Override
					public void onObjCmdReceipt(ObjCmdReceipt objCmdReceipt) throws Exception {
						logger.info("onObjCmdReceipt: {}", objCmdReceipt.toJSONObject());
					}
					@Override
					public void onReceiptTimeout() throws Exception {
						logger.info("onReceiptTimeout");
					}
					@Override
					public void onObjCmdReply(ObjCmdReply objCmdReply) throws Exception {
						logger.info("onObjCmdReply: {}", objCmdReply.toJSONObject());
						Packet packet = Packet809Utils.makePacketFromDecodedBytes(objCmdReply.getRawData(), true);
						logger.info("packet: {}", packet.toJSONObject());
					}
					@Override
					public void onReplyTimeout() throws Exception {
						logger.info("onReplyTimeout");
					}
				});

				logger.info("{}{}=======>业户start===>自动定时任务循环修改策略设置表======start{}{}" 
				+ format.format(new Date()));
				strategy.setRowerTime(format.format(new Date()));	// 2.修改策略设置表的时间
				strategy.setRowver(String.valueOf(strategy.getId()));// 更新时->保存策略设置的主键id
				int count = updateStrategys(strategy);
				if (count > 0) {// 修改成功
					logger.info("{}{}=========>{}{}业户自动定时任务. 修改时间成功{}{} " + format.format(new Date()) + ".");
					// 3.插入MONGODB
					logger.info("{}{}=======>业户start=====>自动定时任务{}{}======>insert Mongodb======start{}{}"
							+ format.format(new Date()));
					// 查岗时间
					Date check_time = new Date();
					// 保存post_check表
					String _id = UUID.randomUUID().toString().replace("-", "");
					EntCheck entCheck = new EntCheck();
					entCheck.set_id(_id);											// check_id UUID
					entCheck.setChecker(strategy.getUserName());					// 查岗人
					entCheck.setCheck_time(check_time);								// 查岗时间
					entCheck.setCheck_content(strategy.getQuestion());				// 查岗内容
					entCheck.setAnswer(strategy.getAnswer());						// 答案
					entCheck.setCheck_type(1); 										// 查岗方式  1:手动  2:自动
					entCheck.setTotal_count(1);										// 总查岗指令数
					entCheck.setSucc_reply_count(0);								// 成功回复指令数
					entCheck.setFail_reply_count(0);								// 失败回复指令数
					entCheck.setNo_reply_count(1);									// 无回复指令数
					// 保存MONGODB
					mgTemplete.insertOne(MongodbConfig.MONGODB_DB, MongodbConfig.MONGODB_TABLE_POST_CHECK,
							entCheck);
					// 保存post_check_cmd表
					EntCheckCmd entCheckCmd = new EntCheckCmd();
					entCheckCmd.set_id(object_type+":"+object_id+":"+info_id);  // <object_type:object_id:info_id>
					entCheckCmd.setCheck_id(_id); 								// post_check 表 _id UUID
					entCheckCmd.setCheck_unit_id(strategy.getCheckTargetId());	// 查岗业户ID
					entCheckCmd.setCheck_unit_name(checkUnitName);				// 查岗业户名称
					entCheckCmd.setInfo_id(info_id); 							// 查岗指令info_id随机数
					entCheckCmd.setObject_id(object_id);
					entCheckCmd.setCheck_time(check_time); 						// 查岗时间
					entCheckCmd.setCheck_result(4);								// 查岗结果 1:正确 2:错误 3:超时 4:未应答  (默认4:未应答)
					entCheckCmd.setCheck_content(strategy.getQuestion());		// 查岗内容
					entCheckCmd.setAnswer(strategy.getAnswer());				// 答案
					// 保存MONGODB
					mgTemplete.insertOne(MongodbConfig.MONGODB_DB, MongodbConfig.MONGODB_TABLE_POST_CHECK_CMD, entCheckCmd);
					logger.info(
							"{}{}=======>业户end=====>自动定时任务{}{}======>insert Mongodb======end{}{}"
					+ format.format(new Date()));
				} else {
					logger.info("{}{}=========>{}{}业户自动定时任务. 修改时间失败{}{} " 
					+ format.format(new Date()) + ".");
				}
				logger.info("{}{}=======>业户end=====>自动定时任务循环修改策略设置表======end{}{}" + 
				format.format(new Date()));
			} catch (Exception e) {
				e.printStackTrace();
			}finally{
				// 所有逻辑执行完后 关闭链接
				cmdProducer.getClient().closeResources();// 关闭链接
			}
		}else{
			logger.info("{}{}=====================>cmd项目链接失败=====================================》" + 
					format.format(new Date()));
		}
		

	}

	@SuppressWarnings("static-access")
	public void task(Strategy strategy) {
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		logger.info("{}{}=======>区域自动定时任务循环修改策略设置表======start{}{}" + format.format(new Date()));
		// 2.修改策略设置表的时间
		String rowerTime = format.format(new Date());
		strategy.setRowerTime(rowerTime);
		// 更新时->保存策略设置的主键id
		strategy.setRowver(String.valueOf(strategy.getId()));
		int count = updateStrategys(strategy);
		// 修改成功
		if (count > 0) {
			logger.info("{}{}=========>{}{}区域自动定时任务. 修改时间成功{}{} " +
					format.format(new Date()) + ".");
		} else {
			logger.info("{}{}=========>{}{}区域自动定时任务. 修改时间失败{}{} " +
					format.format(new Date()) + ".");
		}
		logger.info("{}{}=======>区域自动定时任务循环修改策略设置表======end{}{}" +
				format.format(new Date()));

		// 3.插入MONGODB
		logger.info("{}{}=======>区域自动定时任务{}{}======>insert Mongodb======start{}{}" + 
				format.format(new Date()));
		// 查岗id
		int check_id = ThreadLocalRandom.current().nextInt();
		int check_type = strategy.getCheckType(); // 取查岗方式（即自动2）
		int check_area_id = strategy.getCheckTargetId();
		String checkAreaName="";
		Map<String, String> map =  queryAreaName(strategy.getCheckTargetId());
		if(map != null){
			checkAreaName = map.get("name") == null ? "" : map.get("name").toString();
		}
		if(checkAreaName.equals("")){
			logger.info("{}{}=======>区域名称查询为空=================》" + 
					format.format(new Date()));
		}
		
		// MONGODB _id= objectType:ObjectId:InfoId
		AreaCheck areaCheck = new AreaCheck();
		areaCheck.set_id(check_type + ":" + check_area_id + ":" + check_id);		// _id: "<check_type:check_area_id:check_id>",
		areaCheck.setCheck_time(new Date()); 										// 查岗时间
		areaCheck.setCheck_area_id(strategy.getCheckTargetId());					// 查岗区域ID
		areaCheck.setCheck_area_name(checkAreaName); 								// 查岗区域名称
		areaCheck.setCheck_content(strategy.getQuestion()); 						// 查岗内容
		areaCheck.setChecker(strategy.getUserName()); 								// 查岗人 (当前登录人)
		areaCheck.setAnswer(strategy.getAnswer()); 									// 答案
		areaCheck.setCheck_id(check_id); 											// 查岗ID(暂时随机数)
		areaCheck.setCheck_type(2); 												// 查岗方式 1:手动 2:自动
		areaCheck.setCheck_result(4); 												// 查岗结果 1:正确 2:错误 3:超时 4:未应答  (默认4:未应答)
		// 保存MONGODB
		mgTemplete.insertOne(MongodbConfig.MONGODB_DB, MongodbConfig.MONGODB_TABLE_POST_CHECK_INNER, 
				areaCheck);
		logger.info("{}{}=======>区域自动定时任务{}{}=======>insert Mongodb======end{}{}" + format.format(new Date()));

	}
	
	
	/**
	 *  当前区域查岗应答->区域查岗应答->系统时间15分钟之前的数据改成[超时：3]
	 */			
	public void areaCheckReplyTask() {
		ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
		executor.scheduleAtFixedRate(new AreaCheckReplyTaskServer(), 0, config.areaCheckTaskTimers, // 15分钟执行一次
				TimeUnit.MILLISECONDS);
		logger.info("区域查岗应答任务{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{{}进入线程方法{}{} " +
					System.currentTimeMillis());
	}
	/**
	 * 更改超时状态线程
	 * @author Tan
	 *
	 */
	class AreaCheckReplyTaskServer implements Runnable {
		@SuppressWarnings("static-access")
		@Override
		public void run() {
			logger.info(">=====================区域查岗应答线程任务======================>");
			try {
				// 默认查询未应答数据
				int check_result = CheckResult.CHECK_RESULT_4;
				
				long curren = System.currentTimeMillis();// 系统时间
				curren = curren - config.areaCheckTaskTimers;
				Date startTime = new Date(curren);
				Document dateDoc = new Document("$lte",startTime);
				// where 条件
				BasicDBObject filter = new BasicDBObject()
									.append("check_result", check_result)
									.append("check_time", dateDoc);
				
				// 需要修改的字段			
				Document replacement = new Document();
				replacement.put("check_result", CheckResult.CHECK_RESULT_3);	
				Document update = new Document("$set",replacement);		
				
				// 查询到数据只修改、无数据不插入
				UpdateOptions options = new UpdateOptions().upsert(false);
				logger.info("{}{}=====>filter"+filter+"=====>update"+update+"=======>options"+options);
				mgTemplete.getCollection(MongodbConfig.MONGODB_DB, MongodbConfig.MONGODB_TABLE_POST_CHECK_INNER)
						  .updateMany(filter, update, options);
			} catch (Exception e) {
				// TODO: handle exception
			}
			
		}
		
	}
	

}
